feat(circleci): add read/workflow insights components#3235
feat(circleci): add read/workflow insights components#3235bitdeckai wants to merge 1 commit intosuperplanehq:mainfrom
Conversation
| if err != nil { | ||
| return err | ||
| } | ||
| workflow, err := client.GetWorkflow(config.WorkflowID) |
There was a problem hiding this comment.
Workflow data silently lost due to typed struct
Medium Severity
The GetWorkflow component calls client.GetWorkflow() which unmarshals into WorkflowResponse — a struct with only 5 fields (id, name, status, created_at, stopped_at). The CircleCI API returns additional fields like pipeline_id, pipeline_number, project_slug, started_by, and tag, all silently dropped during deserialization. When Emit() calls json.Marshal() on the output, only those 5 fields are preserved. The same data loss affects GetLastWorkflow via GetPipelineWorkflows(). All the other new read components correctly use map[string]any to preserve complete API responses.
Additional Locations (1)
| return map[string]any{ | ||
| "pipeline": pipelineResp, | ||
| "workflows": []any{}, | ||
| }, nil |
There was a problem hiding this comment.
Inconsistent pipeline field shape across code paths
Medium Severity
When no pipelines are found, the pipeline field is set to pipelineResp — the full paginated list response (containing items, next_page_token, etc.). When pipelines are found, pipeline is set to firstItem — a single pipeline object (containing id, number, state, etc.). Downstream consumers processing result["pipeline"] will encounter a completely different schema depending on whether pipelines exist, likely causing failures when accessing expected fields like id.
Additional Locations (1)
Signed-off-by: bitdeckai <[email protected]>
45c93f8 to
32c0ff5
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 3 potential issues.
Bugbot Autofix is OFF. To automatically fix reported issues with Cloud Agents, enable Autofix in the Cursor dashboard.
| } | ||
|
|
||
| func (c *Client) GetWorkflowTestMetrics(projectSlug, workflowName string, filters map[string]string) (map[string]any, error) { | ||
| path := fmt.Sprintf("%s/insights/%s/workflows/%s/test-metrics%s", baseURL, projectSlug, workflowName, buildQueryString(filters)) |
There was a problem hiding this comment.
Workflow name not URL encoded in path
High Severity
The workflowName parameter is directly interpolated into the URL path without URL encoding. Workflow names containing spaces, slashes, or special characters will result in malformed URLs and API request failures. The url.PathEscape function wraps path parameters elsewhere in the codebase (see AWS Lambda and Dash0 integrations).
| } | ||
|
|
||
| pipelineID, _ := firstItem["id"].(string) | ||
| workflows, err := c.GetPipelineWorkflows(pipelineID) |
There was a problem hiding this comment.
Missing validation after pipeline ID type assertion
Low Severity
After the type assertion pipelineID, _ := firstItem["id"].(string), the code doesn't check if pipelineID is empty before using it. If the assertion fails or the ID is missing, an empty string gets passed to GetPipelineWorkflows, causing a confusing HTTP error instead of a clear error message. The existing pattern in run_pipeline.go lines 387-390 checks for empty strings after similar type assertions.
| "workflow": workflow, | ||
| "jobs": jobs, | ||
| } | ||
| return ctx.ExecutionState.Emit(core.DefaultOutputChannel.Name, "circleci.workflow", []any{output}) |
There was a problem hiding this comment.
Different data structures use same event type
Medium Severity
Both GetWorkflow and GetLastWorkflow emit events with type "circleci.workflow", but they output completely different data structures. GetWorkflow emits {workflow, jobs} while GetLastWorkflow emits {pipeline, workflows}. Downstream consumers cannot reliably parse these events because the structure varies by source. In other integrations like GitHub, components that emit the same event type always emit consistent data structures.


Summary
Adds five new CircleCI integration components and client methods to support read/insights use cases requested in #3223.
New components
What changed
Notes
Closes #3223